/**
 * 
 */
package de.cbf.cam.dsa.inventory.composites;

import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;
import java.util.List;

import org.eclipse.swt.SWT;
import org.eclipse.swt.SWTException;
import org.eclipse.swt.dnd.DND;
import org.eclipse.swt.dnd.DragSource;
import org.eclipse.swt.dnd.DragSourceAdapter;
import org.eclipse.swt.dnd.DragSourceEvent;
import org.eclipse.swt.dnd.DropTarget;
import org.eclipse.swt.dnd.DropTargetAdapter;
import org.eclipse.swt.dnd.DropTargetEvent;
import org.eclipse.swt.dnd.Transfer;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Label;

import de.cbf.cam.dsa.inventory.dialogs.WeaponStyleChooseDialog;
import de.cbf.cam.dsa.model.ModelBase;
import de.cbf.cam.dsa.model.entities.BattleChar;
import de.cbf.cam.dsa.model.entities.OneNPC;
import de.cbf.cam.dsa.model.entities.WeaponStyle;
import de.cbf.cam.dsa.model.entities.constants.WeaponSpecialConstants;
import de.cbf.cam.dsa.model.entities.items.Item;
import de.cbf.cam.dsa.model.entities.items.transfers.WeaponTransfer;
import de.cbf.cam.dsa.model.entities.weapon.OneWeapon;
import de.cbf.cam.dsa.model.entities.weapon.WeaponInUse;

/**
 * @author Nebelritter
 *
 */
public class CompositeWeaponHand extends Composite {
	
	private CompositeWeaponDisplay 		weaponDisplay;
	private CompositeWeaponTalentDisplay weaponTalentDisplay;
	
	private OneNPC 	character;
	private WeaponInUse	weapon;
	
	private String wearPosition = "WeaponHand";
	
	private boolean weaponDragPossible = true;
	
	private PropertyChange characterPropertyChange = new PropertyChange();
	/**
	 * @param parent
	 * @param style
	 */
	public CompositeWeaponHand(Composite parent, int style) {
		super(parent, style);
		
		GridLayout layout = new GridLayout(2,false);
		layout.marginHeight = 0;
		layout.marginWidth	= 0;
		setLayout(layout);

		weaponDisplay = new CompositeWeaponDisplay(this, style);
		weaponDisplay.setLayoutData(new GridData(SWT.FILL,SWT.FILL,true,true,1,1));
		
		weaponTalentDisplay = new CompositeWeaponTalentDisplay(this, style);
		weaponTalentDisplay.setLayoutData(new GridData(SWT.FILL,SWT.FILL,true,true,1,1));	
		
		buildDropTarget();
		buildDragSource();
	}
	protected void buildDragSource(){
		Label dragSourceLabel = weaponDisplay.provideDragSourceLabel();
		if(dragSourceLabel!=null){
			Transfer[] types = new Transfer[] { WeaponTransfer.getInstance()};
			
		    DragSource source = new DragSource(dragSourceLabel, DND.DROP_MOVE);
		    source.setTransfer(types);
		   
		    source.addDragListener(new WeaponDragListener());	
		}
	}
	
	protected void buildDropTarget(){
		Transfer[] types = new Transfer[] { WeaponTransfer.getInstance() };
		DropTarget target = new DropTarget(this, DND.DROP_MOVE | DND.DROP_DEFAULT);
	    target.setTransfer(types);
	    
	    target.addDropListener(new WeaponDropListener());
	}
	
	protected OneWeapon checkGuidWeapon(String guid){
		for(int i = 0;i<character.getItems().size();i++){
			Item item = character.getItems().get(i);
			if(item.getGuid().equals(guid)){
				if (item instanceof OneWeapon) {
					OneWeapon weapon = (OneWeapon) item;
					return weapon;
				}
			}
		}
		return null;		
	}
	
	
	
	public String getWearPosition() {
		return wearPosition;
	}


	public void setWearPosition(String wearPosition) {
		this.wearPosition = wearPosition;
	}
	
	public void setData(OneNPC character,WeaponInUse weapon){
		if(this.character!=null){
			this.character.propertyChangeSupport.removePropertyChangeListener(characterPropertyChange);
		}
		this.character 	= character;
		this.character.propertyChangeSupport.addPropertyChangeListener(characterPropertyChange);
		this.weapon		= weapon;
		fillDisplay();
	}

	public void setWeapon(WeaponInUse weapon) {
		this.weapon	= weapon;
		fillDisplay();		
	}
	
	public void setWeapon(OneWeapon weapon) {
		String styleTalent="";
		//check which styles are possible for this character
		List<WeaponStyle> possibleStyles = new ArrayList<WeaponStyle>();
		for(int i = 0;i < weapon.getStyles().size();i++){
			WeaponStyle style = weapon.getStyles().get(i);
			if(style.testCharacterForStyleAvailble(character)){
				possibleStyles.add(style);
			}
		}
		if(possibleStyles.size()>0){
			//just one style so choose this without asking
			styleTalent = possibleStyles.get(0).getTalentName();
			weaponTalentDisplay.setTalentChoiceEnabled(false);
		}
		if(weapon.getStyles().size()>1){
			//more than one style -> ask which to use		
			styleTalent = askForWeaponStyle(possibleStyles);
			weaponTalentDisplay.setTalentChoiceEnabled(true);
		}		
		WeaponInUse weaponInUse = character.drawWeapon(weapon,wearPosition,styleTalent); 
		if(weaponInUse != null){					
			setWeapon(weaponInUse);
		}else{
			 System.err.println("weapon draw error");
		}		
	}	
	
	public WeaponInUse getWeapon(){
		return weapon;
	}
	public boolean isWeaponDragPossible() {
		return weaponDragPossible;
	}
	public void setWeaponDragPossible(boolean weaponDragPossible) {
		this.weaponDragPossible = weaponDragPossible;
	}
	
	public void fillDisplay(){
		weaponDisplay.setWeapon(weapon);
		weaponTalentDisplay.setData(character, weapon);			
	}


	public void disable() {
		weaponDisplay.disable();
		weaponTalentDisplay.disable();
	}
	
	public void enable() {
		weaponDisplay.enable();
		weaponTalentDisplay.enable();
	}
	
	
	private class WeaponDragListener extends DragSourceAdapter{
		public void dragSetData(DragSourceEvent event) {			
			if (WeaponTransfer.getInstance().isSupportedType(event.dataType)) {
				event.data = weapon.getWeapon();// store weaponMain
			}				  
		}

		@Override
		public void dragFinished(DragSourceEvent event) {			
			if (event.detail == DND.DROP_MOVE){
				System.out.println("Removed weaponMain from: "+wearPosition); //refill table for changed wear /or notified via listener
				//set unarmed weapon
				WeaponInUse unarmed = ModelBase.getInstance().provideUnarmed().useIt(character,"Raufen");
				//check if old weapon was two handed, and if set character second weapon to unarmed too
				if((weapon.getWeapon().getSpecialStates()&WeaponSpecialConstants.STATE_twoHand) !=0){
					//weapon is two-handed 
					character.setWeapon(unarmed, OneNPC.Hand_Second);
				}
				setWeapon(unarmed);
				
				fillDisplay();
			}			 
		}

		@Override
		public void dragStart(DragSourceEvent event) {
			if(weapon==null||weapon.getWeapon().getName().equals(OneWeapon.UNARMED)||!weaponDragPossible){
				//no weaponMain -> no drag
				event.doit = false;
			}			
		}		
	}
	
	
	private class WeaponDropListener extends DropTargetAdapter{
	
		public void dragEnter(DropTargetEvent event) {		       	
			if (event.detail == DND.DROP_DEFAULT) {
				try{
					WeaponTransfer.getInstance().nativeToJava(event.currentDataType);//check if weapon in it					
					if ((event.operations & DND.DROP_MOVE) != 0) {					
						//check if hand is empty
	   				 	WeaponInUse weaponAlreadyInHand = CompositeWeaponHand.this.weapon;
	   				 	if(weaponAlreadyInHand!= null){
		   				 	String typeInUse = weaponAlreadyInHand.getWeapon().getWeaponType();
		   				 	if(weaponAlreadyInHand ==null||typeInUse.equals(OneWeapon.UNARMED)){
		   				 		event.detail = DND.DROP_MOVE;
		   				 	}else{
		   				 		//hand not empty -> no drop
		   				 		event.detail = DND.DROP_DEFAULT;//DND.DROP_NONE
		   				 	}		
	   				 	}   				 					
					} else {
						event.detail = DND.DROP_NONE;
					}
				}catch (SWTException e) {
					event.detail = DND.DROP_NONE;
				}
			}		 	    
		}	    		
   	
		public void dragOver(DropTargetEvent event) { 
			 event.feedback = DND.FEEDBACK_SCROLL|DND.FEEDBACK_SELECT;			
		}
     
		public void drop(DropTargetEvent event) {
			 if (WeaponTransfer.getInstance().isSupportedType(event.currentDataType)) {	            
				 OneWeapon weapon = (OneWeapon)event.data;
				 if(weapon!=null){	
					setWeapon(weapon);					 
				 }
			 }		        		
		}

		
		@Override
		public void dragOperationChanged(DropTargetEvent event) {
			 if (event.detail == DND.DROP_DEFAULT) {
	            if ((event.operations & DND.DROP_MOVE) != 0) {
	                event.detail = DND.DROP_MOVE;
	            } else {
	                event.detail = DND.DROP_NONE;
	            }
	        }	 	       
		}
		
	}

	private class PropertyChange implements PropertyChangeListener{
		@Override
		public void propertyChange(PropertyChangeEvent event) {
			Object object = event.getNewValue();
			if (object instanceof BattleChar) {
				BattleChar character = (BattleChar) object;
				WeaponInUse weapon = character.getWeapon(wearPosition);
				if(weapon!=null){
					setWeapon(weapon);
				}
			}			
		}		
	}

	@Override
	public void dispose() {
		character.propertyChangeSupport.removePropertyChangeListener(characterPropertyChange);
	}
	
	private String askForWeaponStyle(List<WeaponStyle> styles) {
		WeaponStyleChooseDialog dialog = new WeaponStyleChooseDialog(getShell());
		dialog.create();
		dialog.setData(styles);
		WeaponStyle styleChosen = dialog.openForResult();
		return styleChosen.getTalentName();
	}
}
